# coding=utf-8
import re


class Template(object):
    """
    模板，可以解析变量值，解析循环和判断
    """

    def __init__(self, template_param, context):
        """
        :param template_param: 模板文字
        :param context: 上下文函数，所有调用的函数必须这样传进去
        :return: 模板对象
        """
        self.template = template_param
        self.context = context
        self.tokens = re.split(r"({{.*?}}|{%.*?%}|{#.*?#})", template_param)

    def compile(self, obj):
        """
        编译模板，将值填入模板
        :param obj: 要替换的文字
        :return: 编译后的模板
        """

        # 用于保存模板编译之后的内容
        buffer = []
        # for循环中保存的代码栈
        for_stack_code = []
        # for循环中使用的对象
        for_stack_obj = []
        # for循环中使用对象相对的key
        for_stack_obj_key = []

        # 循环每一句模板，进行解析
        for w in self.tokens:
            # 解析普通表达式
            if w.startswith("{{"):
                # 如果不是for循环里，则直接解析值
                if len(for_stack_obj) == 0:
                    exp = w[2: -2].strip()
                    buffer.append(self._expr_code(exp, obj))
                # 如果是在for循环里，则添加到for代码栈
                else:
                    for_stack_code.append(w)
            # 解析特殊表达式
            elif w.startswith("{%"):
                exp = w[2: -2].strip()
                # 解析for循环
                if exp.startswith("for"):
                    for_codes = exp.split()
                    list_obj = self._get_dot_value(for_codes[3], obj)
                    for_stack_obj.append(list_obj)
                    for_stack_obj_key.append(for_codes[1])
                # 解析if
                elif exp.startswith("if"):
                    if_code = exp.split()

                    pass
                # 解析elseif
                elif exp.startswith("elif"):
                    pass
                # 解析else
                elif exp.startswith("else"):
                    pass
                # 解析if结束
                elif exp.startswith("endif"):
                    pass
                # 解析for循环的关闭
                elif exp.startswith("endfor"):
                    list_obj = for_stack_obj.pop()
                    key = for_stack_obj_key.pop()
                    for obj_item in list_obj:
                        for code in for_stack_code:
                            if code.startswith("{{"):
                                exp = code[2: -2].strip()
                                buffer.append(self._expr_code(exp, {key: obj_item}))
                            else:
                                buffer.append(code)
            # 如果不是表达式，则直接处理
            else:
                if w:
                    # 如果不是for循环，就直接加到输出中
                    if len(for_stack_obj) == 0:
                        buffer.append(w)
                    # 如果是for循环里面，则加到for循环代码栈，进行循环解析
                    else:
                        for_stack_code.append(w)
        return "".join(buffer)

    def _expr_code(self, expr, obj):
        """
        获取变量表达式的函数
        :param expr: 解析的表达式
        :return: 解析后的值
        """
        if "|" in expr:
            pipes = expr.split("|")
            code = pipes[0]
            value = self._get_dot_value(code, obj)
            r = self.context.get(pipes[1])(value)
            return r
        else:
            return self._get_dot_value(expr, obj)

    def _get_dot_value(self, dot_str, obj):
        """
        获取数据字典"."点内的内容
        :param dot_str: 未解析的点表达式
        :param obj 值列表
        :return: 取到的最后的值
        """
        dots = dot_str.split(".")
        value = obj
        for d in dots:
            value = value.get(d)
        return value


if __name__ == '__main__':
    templateStr = """
        <p>{{user.name}}</p>
        <p>{{test|upper}}</p>
        <ul>
        {% for d in l %}
            <li>{{d.username}}</li>
        {% endfor %}
        </ul>
    """
    result = Template(templateStr, {"upper": str.upper}).compile({
        "user": {
            "name": "xiejingyang"
        },
        "test": "hehe",
        "isAdmin": "true",
        "l": [{"username": "a"}, {"username": "b"}, {"username": "c"}]
    })
    print(result)
